package com.wzcl.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.wzcl.app.config.RabbitMqConfiguration;
import com.wzcl.app.dao.model.Delivery;
import com.wzcl.app.dao.model.Orders;
import com.wzcl.app.dao.model.SendPath;
import com.wzcl.app.dao.repository.DeliveryRepository;
import com.wzcl.app.model.common.BusinessException;
import com.wzcl.app.model.common.CodeMsg;
import com.wzcl.app.model.common.MyPage;
import com.wzcl.app.model.common.WZCL;
import com.wzcl.app.model.dto.DeliveryDto;
import com.wzcl.app.service.DeliveryService;
import com.wzcl.app.service.OrderService;
import com.wzcl.app.utils.MD5Util;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;

@Log4j2
@Service
@PropertySource({"classpath:application-config.properties"})
public class DeliveryServiceImpl implements DeliveryService {
    //实时查询请求地址
    private static final String SYNQUERY_URL = "http://poll.kuaidi100.com/poll/query.do";

    @Value("${kuaiDi.key}")
    private String key;

    @Value("${kuaiDi.customer}")
    private String customer;

    @Value("${kuaiDi.resultv2}")
    private String resultv2;


    @Autowired
    private DeliveryRepository deliveryRepository;

    @Autowired
    private OrderService orderService;

    @Override
    public Delivery delDeliveryById(Integer id) {
        //校验获取
        Delivery delivery = getAndCheckById(id);
        //删除
        delivery.setState(WZCL.STATE.IS_DELETE);
        return deliveryRepository.save(delivery);
    }

    @Override
    public Delivery getDeliveryById(Integer id) {
        return deliveryRepository.findById(id).orElse(null);
    }


    @Override
    public Delivery getAndCheckById(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少物流信息ID");
        }
        Delivery delivery = getDeliveryById(id);
        if (delivery == null) {
            throw new BusinessException(CodeMsg.DELIVERY_NOT_EXIST);
        }
        return delivery;
    }

    @Override
    public Delivery getDelivery(DeliveryDto deliveryDto) {
        Delivery delivery = getDeliveryById(deliveryDto.getId());
        if (delivery != null && !delivery.getUserPhone().equals(deliveryDto.getUserPhone())) {
            return null;
        }
        return delivery;
    }

    @Override
    public Delivery updateDeliver(DeliveryDto deliveryDto) {
        Delivery delivery = deliveryRepository.findByUserPhoneAndOrderNo(deliveryDto.getUserPhone(), deliveryDto.getOrderNo());
        if (delivery == null) {
            throw new BusinessException(CodeMsg.DELIVERY_NOT_EXIST);
        }
        if (!WZCL.DELIVERY_STATE.BE_DELIVER.equals(delivery.getDeliveryState())) {
            throw new BusinessException(CodeMsg.DELIVERY_STATE_ERROR, "当前订单不允许修改");
        }
        //校验快递公司
        WZCL.DELIVERY_COMPANY company = WZCL.DELIVERY_COMPANY.getByValue(deliveryDto.getCompany());
        if (company == null) {
            throw new BusinessException(CodeMsg.DELIVERY_COMPANY_ERROR);
        }
        delivery.setDeliveryNo(deliveryDto.getDeliveryNo());
        delivery.setDeliveryCompany(company.getValue());
        //更新订单状态 添加订单信息  待发货--->待收货
        delivery.setDeliveryState(WZCL.DELIVERY_STATE.BE_RECEIVED);
        delivery.setSendTime(new Date());
        orderService.changeDeliveryState(delivery.getOrderNo(), WZCL.DELIVERY_STATE.BE_RECEIVED);
        if (StringUtils.isNotBlank(deliveryDto.getDescription())) {
            delivery.setDescription(deliveryDto.getDescription());
        }
        return deliveryRepository.save(delivery);
    }


    @Override
    public List<Delivery> getDeliveryList(DeliveryDto deliveryDto) {
        return deliveryRepository.findAll(getSpecification(deliveryDto), deliveryDto.getSort());
    }

    @Override
    public MyPage<Delivery> getDeliveryPage(DeliveryDto deliveryDto) {
        Page<Delivery> all = deliveryRepository.findAll(getSpecification(deliveryDto), deliveryDto.getPageable());
        ArrayList<Delivery> list = new ArrayList<>(all.getContent());
        Collections.reverse(list);
        MyPage<Delivery> myPage = new MyPage<>();
        myPage.setContent(list);
        myPage.setTotalElements(all.getTotalElements());
        return myPage;
    }

    /*
    根据快递单查询快递信息
     */
    @Override
    public String queryDeliveryInfo(DeliveryDto deliveryDto) {
        //校验
        Delivery delivery = getAndCheckById(deliveryDto);
        //用户校验(避开管理员)
        if (StringUtils.isNotBlank(deliveryDto.getUserPhone())) {
            if (!delivery.getUserPhone().equals(deliveryDto.getUserPhone())) {
                throw new BusinessException(CodeMsg.USER_NOT_MATCH);
            }
        }
        return synQueryData(delivery.getDeliveryCompany(), delivery.getDeliveryNo());
    }

    //确认收货
    @Override
    public Delivery confirm(Integer id, String phone) {
        //校验获取
        Delivery delivery = getAndCheckById(id);
        //待收货 -> 收货
        if (!WZCL.DELIVERY_STATE.BE_RECEIVED.equals(delivery.getDeliveryState())) {
            throw new BusinessException(CodeMsg.DELIVERY_STATE_ERROR, "无法确认收货");
        }
        //用户校验(避开管理员)
        if (StringUtils.isNotBlank(phone)) {
            if (!delivery.getUserPhone().equals(phone)) {
                throw new BusinessException(CodeMsg.USER_NOT_MATCH);
            }
        }
        delivery.setDeliveryState(WZCL.DELIVERY_STATE.RECEIVED);
        orderService.changeDeliveryState(delivery.getOrderNo(), WZCL.DELIVERY_STATE.RECEIVED);
        return deliveryRepository.save(delivery);
    }

    private Specification<Delivery> getSpecification(DeliveryDto deliveryDto) {
        return new Specification<Delivery>() {
            @Override
            public Predicate toPredicate(Root<Delivery> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (StringUtils.isNotBlank(deliveryDto.getUserPhone())) {
                    predicates.add(criteriaBuilder.equal(root.get("userPhone"), deliveryDto.getUserPhone()));
                }
                if (deliveryDto.getDeliveryState() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("deliveryState"), deliveryDto.getDeliveryState()));
                }
                predicates.add(criteriaBuilder.equal(root.get("state"), WZCL.STATE.NOT_DELETE));
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }

    /*
    消费快递队列消息
     */
    @RabbitListener(queues = RabbitMqConfiguration.DIRECT_QUEUE_PATH)
    public void OrderPathConsumer(String orderStr) {
        log.info("mq:{} received massage：{}", RabbitMqConfiguration.DIRECT_QUEUE_PATH, orderStr);
        Orders orders = JSON.parseObject(orderStr, Orders.class);
        Orders order = orderService.getOrderById(orders.getId());
        if (order == null) {
            throw new BusinessException(CodeMsg.ORDERS_NOT_EXIST);
        }
        Delivery delivery = new Delivery();
        //设置参数
        delivery.setOrderNo(order.getNo());
        delivery.setUserPhone(order.getUserPhone());
        //快递参数
        SendPath sendPath = order.getSendPath();
        delivery.setName(sendPath.getName());
        delivery.setPhone(sendPath.getPhone());
        delivery.setPath(sendPath.getPath());
        delivery.setPathInfo(sendPath.getPathInfo());
        //初始化状态，目前状态跟新来自手动
        delivery.setDeliveryState(WZCL.DELIVERY_STATE.BE_DELIVER);
        delivery.setState(WZCL.STATE.NOT_DELETE);
        deliveryRepository.save(delivery);
    }


    /**
     * 实时查询快递单号
     *
     * @param com 快递公司编码
     * @param num 快递单号
     * @return
     */
    private String synQueryData(String com, String num) {

        StringBuilder param = new StringBuilder("{");
        param.append("\"com\":\"").append(com).append("\"");
        param.append(",\"num\":\"").append(num).append("\"");
        param.append(",\"resultv2\":").append(Integer.valueOf(resultv2));
        param.append("}");
        Map<String, String> params = new HashMap<String, String>();
        params.put("customer", customer);
        String sign = MD5Util.encode(param + key + customer);
        params.put("sign", sign);
        params.put("param", param.toString());

        return this.post(params);
    }

    /**
     * 发送post请求
     */
    public String post(Map<String, String> params) {
        StringBuffer response = new StringBuffer("");

        BufferedReader reader = null;
        try {
            StringBuilder builder = new StringBuilder();
            for (Map.Entry<String, String> param : params.entrySet()) {
                if (builder.length() > 0) {
                    builder.append('&');
                }
                builder.append(URLEncoder.encode(param.getKey(), "UTF-8"));
                builder.append('=');
                builder.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
            }
            byte[] bytes = builder.toString().getBytes("UTF-8");

            URL url = new URL(SYNQUERY_URL);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(3000);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.setRequestProperty("Content-Length", String.valueOf(bytes.length));
            conn.setDoOutput(true);
            conn.getOutputStream().write(bytes);

            reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

            String line = "";
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
        } catch (Exception e) {
            log.error("快递信息查询调用失败:{} \r\n 堆栈信息:{}", e.getMessage(), BusinessException.collectExceptionStackMsg(e));
        } finally {
            try {
                if (null != reader) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return response.toString();
    }
}

